package ext.wxcp;

import ext.wxcp.anno.MatchAppType;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.cp.api.WxCpConfigStorage;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.bean.WxCpMessage;
import me.chanjar.weixin.cp.bean.WxCpXmlMessage;
import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage;
import play.Logger;
import play.jobs.Job;
import util.extension.ExtensionInvocation;
import util.extension.ExtensionResult;
import util.extension.annotation.ExtensionPoint;
import models.enums.WxcpAppType;

/**
 * 定义微信扩展点.
 */
@ExtensionPoint("Weixin")
public abstract class WxCpInvocation implements ExtensionInvocation<WxCpContext> {

    WxcpAppType wxcpAppType = null;

    private static final ThreadLocal<WxCpContext> _threadLocalWxCpContext = new ThreadLocal<>();

    @Override
    public ExtensionResult execute(WxCpContext context) {

        _threadLocalWxCpContext.set(context);

        context.outMessage = doExecute(context);

        _threadLocalWxCpContext.remove();

        return ExtensionResult.SUCCESS;
    }

    /**
     * 从ThreadLocal中得到当前的WxCpContext
     * @return
     */
    public WxCpContext getContext() {
        return _threadLocalWxCpContext.get();
    }

    /**
     * 处理微信消息响应的代码。
     */
    protected abstract WxCpXmlOutMessage doExecute(WxCpContext context);

    @Override
    public boolean match(WxCpContext context) {

        if (context.appType != getWxcpAppType()) {
            // 应用类型不一致，不处理.
            if (getWxcpAppType() == WxcpAppType.NULL) {
                Logger.info("微信扩展：%s 没有配置正确的@MatchAppType，不能处理任何消息，请检查配置.");
            }
            return false;
        }

        WxCpXmlMessage inMessage = context.inMessage;

        // 如果是文本消息
        if (WxConsts.XML_MSG_TEXT.equals(inMessage.getMsgType()) && matchText(inMessage.getContent())) {
            return true;
        }

        if (WxConsts.XML_MSG_EVENT.equals(inMessage.getMsgType())) {
            String event = inMessage.getEvent();
            String eventKey = inMessage.getEventKey();
            Logger.info("event:%s, eventKey: %s", event, eventKey);
            // 如果是菜单点击事件.
            if (WxConsts.EVT_CLICK.equals(event)) {
                if (getMenuKey() != null && getMenuKey().equals(eventKey)) {
                    // 匹配菜单点击
                    return true;
                }
                if (matchMenuKey(eventKey)) {
                    return true;
                }
            }

            if (matchEvent(event, eventKey)) {
                return true;
            }
        }

        return matchInMessage(context.inMessage);
    }

    private boolean matchInMessage(WxCpXmlMessage inMessage) {
        return false;
    }


    protected boolean matchEvent(String event, String eventKey) {
        return false;
    }

    /**
     * 对于文本类消息，对用户输入的内容进行响应.
     * 所有需要响应文本输入的Invocation使用此类.
     */
    protected boolean matchText(String content) {
        return false;
    }

    /**
     * 提供一个扩展点，使用正则之类的机制来匹配菜单的key，以灵活处理更多的内容.
     *
     * @param menuKey
     * @return
     */
    protected boolean matchMenuKey(String menuKey) {
        return false;
    }

    /**
     * 定义菜单key，如果有值，会检查菜单点击事件，并响应相同key的点击行为.
     *
     * @return 匹配的菜单key；默认为null，不使用
     */
    public String getMenuKey() {
        return null;
    }

    /**
     * 得到当前扩展所对应的应用，如果为NULL值，则所有请求都不会参与处理.
     */
    public WxcpAppType getWxcpAppType() {
        if (wxcpAppType == null) {
            if (this.getClass().isAnnotationPresent(MatchAppType.class)) {
                MatchAppType matchAppType = this.getClass().getAnnotation(MatchAppType.class);
                wxcpAppType = matchAppType.value();
            } else {
                wxcpAppType = WxcpAppType.NULL;
            }
        }
        return wxcpAppType;
    }

    /**
     * 发送异步文本消息给当前的用户.
     */
    public void sendAsyncTextMessage(final String content) {
        final WxCpContext context = getContext();
        new Job() {
            @Override
            public void doJob() throws Exception {
                WxCpConfigStorage wxCpConfigStorage = WeixinCpHelper.getWxCpConfigStorage(context.appType);
                WxCpMessage wxCpMessage = WxCpMessage
                        .TEXT()
                        .agentId(wxCpConfigStorage.getAgentId()) // 企业号应用ID
                        .toUser(context.inMessage.getFromUserName())
                        .content(content)
                        .build();
                WxCpService wxCpService = WeixinCpHelper.getWxCpService(context.wxCpConfigStorage);
                try {
                    wxCpService.messageSend(wxCpMessage);
                } catch (WxErrorException e) {
                    Logger.error(e, "发送消息出现异常");
                }
            }
        } .now();
    }
}
